package com.buss.core.persistence;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SpringSessionContext;
import org.springframework.stereotype.Repository;

import com.buss.core.utils.StringUtil;

@Repository
public class BaseDaoImpl<T extends Serializable> implements BaseDao<T> {

	@Autowired
	private SessionFactory sessionFactory;

	@SuppressWarnings("unused")
	public ResultSet getResultSet(String sql, PersistenceCond cond) {
		Connection conn;
		try {
			conn = SessionFactoryUtils.getDataSource(sessionFactory)
					.getConnection();
			
			PreparedStatement ps = conn.prepareStatement(sql);
			
		} catch (SQLException e) {

			e.printStackTrace();
		}
		return null;
	}

	public void excuteHsql(String hsql, PersistenceCond cond) {
		Query query = getSession().createQuery(hsql);
		setParameter(query, cond);
		query.executeUpdate();
	}

	public void excuteHsql(String hsql,Map<String,Object> map){
		Query query = getSession().createQuery(hsql);
		query.setProperties(map);
		query.executeUpdate();
	}
	
	public void excuteNative(String sql, PersistenceCond cond) {		
		Query query = getSession().createSQLQuery(sql);
		setParameter(query, cond);
		query.executeUpdate();
	}

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@SuppressWarnings("unchecked")
	public T load(Serializable id, Class type) {
		try{
			T t= (T) getSession().load(type, id);
			return t;
		}catch(Exception ex){
			ex.getMessage();
			return null;
		}
	}

	@SuppressWarnings("rawtypes")
	public T get(Serializable id,Class type){
		return (T) getSession().get(type, id);
	}
	
	@SuppressWarnings("unchecked")
	public T loadHsql(String hsql, PersistenceCond cond) {
		Query query = getSession().createQuery(hsql);
		setParameter(query, cond);
		Iterator<T> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public T loadNative(String sql, Class resultEntity, PersistenceCond cond,
			Paginalbe page) {
		Query query = getSession().createSQLQuery(sql).addEntity(resultEntity);
		setParameter(query, cond);
		Iterator<T> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public Object loadNativeSingleValue(String sql, PersistenceCond cond) {

		Query query = getSession().createSQLQuery(sql);
		setParameter(query, cond);
		Iterator<Object> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	private void setParameter(Query query, PersistenceCond cond) {
		String key;
		Object value;
		if (cond != null) {
			for (Iterator<String> iter = cond.getCondition().keySet()
					.iterator(); iter.hasNext();) {
				key = iter.next();
				value = cond.getCondition().get(key);
				if(value instanceof Collection){
					query.setParameterList(key, (Collection) value);
				}else if (value instanceof Object[]){
					query.setParameterList(key, (Object[])value);
				}else{
					query.setParameter(key, value);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	public Object loadSingleValue(String hsql, PersistenceCond cond) {
		Query query = getSession().createQuery(hsql);
		setParameter(query, cond);
		Iterator<Object> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public ResultList<T> queryHsql(String hsql, PersistenceCond cond,
			Paginalbe page) {
		Session session = getSession();
		Query query = session.createQuery(hsql).setCacheable(true);
		ResultList<T> rs = new ResultListImpl<T>();
		setParameter(query, cond);
		if(page != null){
			Query queryCnt = session.createQuery(replaceSql(hsql,true));
			setParameter(queryCnt, cond);
			Iterator<Long> iter = queryCnt.iterate();
			if(iter.hasNext()){
				page.setTotalCount(iter.next().intValue());
			}
			query.setFirstResult(page.getStartNo());
			query.setMaxResults(page.getPageSize());
		}
		rs.setPage(page);
		rs.setData(query.list());
		return rs;
	}

	public ResultList<T> queryHsqlByIter(String hsql,PersistenceCond cond,Paginalbe page){
		Session session = getSession();
		Query query = session.createQuery(hsql).setCacheable(true);
		ResultList<T> rs = new ResultListImpl<T>();
		setParameter(query, cond);
		if(page != null){
			Query queryCnt = session.createQuery(replaceSql(hsql,true));
			setParameter(queryCnt, cond);
			Iterator<Long> iter = queryCnt.iterate();
			if(iter.hasNext()){
				page.setTotalCount(iter.next().intValue());
			}
			query.setFirstResult(page.getStartNo());
			query.setMaxResults(page.getPageSize());
		}
		rs.setPage(page);
		Iterator<T> iter = query.iterate();
		List<T> list = new ArrayList<T>();
		while(iter.hasNext()){
			list.add(iter.next());
		}
		rs.setData(list);
		return rs;
	}
	
	@SuppressWarnings("unchecked")
	public void remove(Serializable id, Class type) {
		Object t = load(id, type);
		getSession().delete(t);
		
	}

	public void remove(Object object) {
		getSession().delete(object);
		
	}

	public void save(Object entity) {
		getSession().save(entity);
		
	}

	@SuppressWarnings("unchecked")
	public T saveOrEdit(Object entity) {
		T t = (T) getSession().merge(entity);
		return t;
	}

	public void saveOrEditBatch(List<Object> entitys) {
		Session session = getSession();
		for (Object obj : entitys) {
			session.merge(obj);
		}
	}

	public void edit(Object entity) {
		
		getSession().merge(entity);
		
	}
	public T loadHsql(String hsql, Map<String, Object> map) {
		Query query = getSession().createQuery(hsql);
		query.setProperties(map);
		Iterator<T> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	public T loadNative(String sql, Class resultEntity,
			Map<String, Object> map, Paginalbe page) {
		Query query = getSession().createSQLQuery(sql).addEntity(resultEntity);
		query.setProperties(map);
		Iterator<T> iter = query.iterate();
		if (iter.hasNext()) {
			return iter.next();
		} else {
			return null;
		}
	}

	public Object loadSingleValue(String hsql, Map<String, Object> map) {
		Query query = getSession().createQuery(hsql);
		query.setProperties(map);
		List<Object> list = query.list();
		if(list.size() > 0){
			return list.get(0);
		}
		return null;
	}

	public Object loadNativeSingleValue(String sql, Map<String, Object> map) {		
		Query query = getSession().createSQLQuery(sql);
		query.setProperties(map);
		List<Object> list = query.list();
		if(list.size() > 0){
			return list.get(0);
		}
		return null;
	}

	public void excuteNative(String sql, Map<String, Object> map) {
		Query query = getSession().createSQLQuery(sql);
		query.setProperties(map);
		query.executeUpdate();
		
	}

	public ResultList<T> queryHsql(String hsql, Map<String, Object> map,
			Paginalbe page) {
		Session session = getSession();
		Query query = session.createQuery(hsql).setCacheable(true);
		ResultList<T> rs = new ResultListImpl<T>();
		query.setProperties(map);
		if(page != null){
			Query queryCnt = session.createQuery(replaceSql(hsql,true));
			queryCnt.setProperties(map);
			Iterator<Long> iter = queryCnt.iterate();
			if(iter.hasNext()){
				page.setTotalCount(iter.next().intValue());
			}
			query.setFirstResult(page.getStartNo());
			query.setMaxResults(page.getPageSize());
		}
		rs.setPage(page);
		rs.setData(query.list());
		return rs;
	}

	public ResultList<T> queryHsqlByIter(String hsql, Map<String, Object> map,
			Paginalbe page) {
		Session session = getSession();
		Query query = session.createQuery(hsql).setCacheable(true);
		ResultList<T> rs = new ResultListImpl<T>();
		query.setProperties(map);
		if(page != null){
			Query queryCnt = session.createQuery(replaceSql(hsql,true));
			queryCnt.setProperties(map);
			Iterator<Long> iter = queryCnt.iterate();
			if(iter.hasNext()){
				page.setTotalCount(iter.next().intValue());
			}
			query.setFirstResult(page.getStartNo());
			query.setMaxResults(page.getPageSize());
		}
		rs.setPage(page);
		Iterator<T> iter = query.iterate();
		List<T> list = new ArrayList<T>();
		while(iter.hasNext()){
			list.add(iter.next());
		}
		rs.setData(list);
		
		return rs;
	}
	
	
	public ResultList<T> queryNative(String sql,SQLQuery query,Map<String,Object> map, Paginalbe page){
		query.setProperties(map);
		ResultList<T> rs = new ResultListImpl<T>();
		if(page != null){
			Query queryCnt = getSession().createSQLQuery(replaceSql(sql,false));
			queryCnt.setProperties(map);
			Iterator<Long> iter = queryCnt.iterate();
			if(iter.hasNext()){
				page.setTotalCount(iter.next().intValue());
			}
			query.setFirstResult(page.getStartNo());
			query.setMaxResults(page.getPageSize());
		}
		rs.setPage(page);
		rs.setData(query.list());
		return rs;

	}
	
	/**
	 * 将Sql替换为取总数的语句
	 * @param sql
	 * @return
	 */
	private String replaceSql(String sqlParam,boolean hqlFlag){
		String sql = sqlParam.trim();
		if(!hqlFlag){
			sql = "select count(1) from (" + sqlParam + ")";
			return sql;
		}
		if (StringUtil.isEmpty(sql)) return "";		
		if(sql.toLowerCase().indexOf("from ") == 0){
			sql = "select * " + sql;
		}
		StringBuffer result = new StringBuffer();
		StringBuffer table = new StringBuffer();
		StringBuffer alias = new StringBuffer();
		Stack<Character> sub = new Stack<Character>();
		int subIndex = 0;
		int fromIndex = 0;
		int index = 0;
		while (index != sql.length()) {
			char c = sql.charAt(index);
			switch (c) {
			case '(':
				subIndex = index;
				sub.push(c);
				break;
			case ')':
				sub.pop();
				break;
			case 'F':
			case 'f':
				if (sub.size() > 0) {
					break;
				}
				String tmp = sql.substring(index, index + 4);
				if (tmp == null || "".equals(tmp)) {
					break;
				}
				if (tmp.equalsIgnoreCase("from")) {
					fromIndex = index;
					index += 4;
				}
				break;
			default:
				if (c == ' ') {
					break;
				}
				if (fromIndex > 0 && sub.size() == 0) {
					if (fromIndex > subIndex || subIndex == 0) {
						while (true) {
							char cc = sql.charAt(index);
							if (cc == ' ') {
								index++;
								break;
							}
							table.append(cc);
							index++;
						}
					}
					while (true) {
						char cc = sql.charAt(index);
//						while(cc == ' ') {
//							index++;
//							cc = sql.charAt(index);
//							continue;
//						}
						if (cc == ' ' || cc == ',') {
							break;
						}
						alias.append(cc);
						index++;
					}
				}
				break;
			}
			if (alias.length() != 0) {
				break;
			}
			index++;
		}
		if(hqlFlag){
			result.append("select count(").append(alias).append(") ").append(sql.substring(fromIndex));
		}//else{
			
		//}
		return result.toString();
		//return sql;
	}
	
	
	
	public static void main(String[] args){
		String sql = "select a,b,c from tb where a = :a and b = :b and c = :c";
		int pos = 0;
		int index = 0;
		pos = sql.indexOf(':');
		while(true){
			
		}
	}

	
}
